/* 贪吃蛇 */
void initGame()
{//初始化游戏
    cbreak();//把终端的CBREAK模式打开
    noecho(); //关闭回显
    curs_set(0); //把光标置为不可见
    keypad(stdscr,true);//使用用户终端的键盘上的小键盘
    srand(time(0)); //设置随机数种子
    hour=minute=second=tTime=0;    //初始化各项数据
    length=1;
    dir.x=1;
    dir.y=0;
    ch='A';
    food.x=rand()%COLS;//COLS屏宽
    food.y=rand()%(LINES-2)+2;
    creatLink();
    setTicker(20);
}
void showInformation()
{ //显示游戏信息（前两行）
    tTime++;
    if(tTime>=1000000)
        tTime=0;
    if(1!=tTime%50)
        return ;
    move(0,3);
    printw("time:%d:%d:%d:%c",hour,minute,second);//显示时间
    second++;
    if(second>NUM)
    {
        second=0;
        minute++;
    }
      //显示长度，等级
    move(1,0);
    int i;
    for(i=0;i<COLS;i++)
        addstr("-");
    move(0,COLS/2-5);
    printw("length:%d",length);
    move(0,COLS-10);
    level=length/3+1;
    printw("level:%d",level);
}

-------------------------------------------------------------------
/* 多路IO */int main()
{
    mkfifo("pipe1",0644);
    mkfifo("pipe2",0644);
    int fd1=open("pipe1",O_RDWR);
    int fd2=open("pipe2",O_RDWR);
    fd_set fs;
    struct timeval timeout={0,0};
    for(;;)
    {
        FD_ZERO(&fs);
        FD_SET(fd1,&fs);
        FD_SET(fd2,&fs);
        FD_SET(STDIN_FILENO,&fs);
        char buf[100];
        if(select(fd2+1,&fs,NULL,NULL,&timeout)>0)
        {
            if(FD_ISSET(0,&fs))
            {//键盘有输入数据
                scanf(" %[^\n]",buf);
                if(strcmp(buf,"quit")==0)
                    break;
                puts(buf);
            }
            if(FD_ISSET(fd1,&fs))
            {//管道pipe1有数据
                int n=read(fd1,buf,sizeof(buf)-1);
                buf[n]='\0';
                printf("pipe1:%s",buf);
            }
            if(FD_ISSET(fd2,&fs))
            {//管道pipe1有数据
                int n=read(fd2,buf,sizeof(buf)-1);
                buf[n]='\0';
                printf("pipe2:%s",buf);
            }
        }
    }
    close(fd1);
    close(fd2);
    unlink("pipe1");
    unlink("pipe2");
    return 0;
}

-------------------------------------------------------------------
/* UDP */int main(int argc,char* argv[])
{
    int skt=socket(AF_INET,SOCK_DGRAM,0);
    struct sockaddr_in s;
    s.sin_family=AF_INET;
    s.sin_addr.s_addr=INADDR_ANY;
    s.sin_port=htons(atoi(argv[1]));
    typedef struct sockaddr* sa;
    if(bind(skt,(sa)&s,sizeof(s))<0)
    {
        return -1;
    }
    char cmd;
    char ip[16];
    short port;
    char text[100];
    for(;;)
    {
        printf("s/r/a/q:");
        scanf(" %c",&cmd);//" %c"跳过空格
        if(cmd=='q')
            break;
        if(cmd=='s')
        {
            scanf("%s%hd %[^\n]",ip,&port,text);
            s.sin_family=AF_INET;
            inet_pton(AF_INET,ip,&s.sin_addr);
            s.sin_port=htons(port);
            sendto(skt,text,strlen(text)+1,0,(sa)&s,sizeof(s));
        }
        else if(cmd=='r')
        {
            socklen_t len=sizeof(s);
            int n=recvfrom(skt,text,sizeof(text),MSG_DONTWAIT,(sa)&s,&len);
            if(n<0)
            {
                puts("没有数据");
                continue;
            }
            inet_ntop(AF_INET,&s.sin_addr,ip,sizeof(ip));
            printf("%s %hd:%s\n",ip,ntohs(s.sin_port),text);
        }
        else if(cmd=='a')
        {
            scanf(" %[^\n]",text);
            sendto(skt,text,strlen(text)+1,0,(sa)&s,sizeof(s));
        }
        else
        {
            puts("非法命令!");
            fflush(stdin);//有些系统可能不管用
        }
    }
    close(skt);
    return 0;
}

-------------------------------------------------------------------
/* 网络通信,客户端 */struct Param{
    int fc;
    char ip[16];
};
void* func(void* p)
{
    struct Param* r=p;
    for(;;)
    {
        char msg[100];
        int n=read(r->fc,msg,sizeof(msg)-1);//取得来自客户端的信息
        if(n<=0)
            break;
        if(msg[0]=='q')//q退出
            break;
        write(r->fc,msg,n);//原样会发到客户端
        msg[n]='\0';//加上字符串结束标记
        printf("%s:%s\n",r->ip,msg);
    }
    close(r->fc);
    printf("%s退出\n",r->ip);
    free(p);//释放动态内存
}
int main()
{
    int fd=socket(AF_INET,SOCK_STREAM,0);
    //AF_INET-ipv4,AF_INET6-ipv6
    //SOCK_STREAM--TCP,SOCK_DGRAM--UDP
    if(fd<0)
    {}
    struct sockaddr_in si;//sockaddr_in6
    si.sin_family=AF_INET;
    si.sin_addr.s_addr=htonl(INADDR_ANY);//INTADDR_ANY就是0,表示本机IP地址
    si.sin_port=htons(8888);//1024以下的端口有专门用途
    //bind(int,sockaddr*,size_t);
    if(bind(fd,(struct sockaddr*)&si,sizeof(si))<0)
    {}
    listen(fd,10);//允许同时有10个接入请求
    for(;;)
    {
        struct sockaddr_in c;//对方套接信息
        socklen_t len=sizeof(c);//必须初始化成本地套接信息长度
        int fc=accept(fd,(struct sockaddr*)&c,&len);//等待客户连接，返回一个跟客户相连的新套接字
        if(fc<0)
            continue;
        char ip[16];
        inet_ntop(AF_INET,&c.sin_addr,ip,sizeof(ip));
        char msg[100];
        sprintf(msg,"YOUR IP:%s,welcome to network",ip);
        write(fc,msg,strlen(msg));
        //close(fc);
        pthread_t id;
        struct Param* p=malloc(sizeof(struct Param));
        p->fc=fc;
        strcpy(p->ip,ip);
        pthread_create(&id,NULL,func,p);
    }
    return 0;
}

/* 网络通信，客户端 */int main(int argc,char* argv[])
{
    int fd=socket(AF_INET,SOCK_STREAM,0);
    if(fd<0)
    {}
    struct sockaddr_in c;
    c.sin_family=AF_INET;
    inet_pton(AF_INET,argv[1],&c.sin_addr);
    //此处应该检查是否成功
    c.sin_port=htons(atoi(argv[2]));
    if(connect(fd,(struct sockaddr*)&c,sizeof(c))<0)
    {}
    char msg[100];
    for(;;)
    {
        int n=read(fd,msg,sizeof(msg));
        //int n=recv(fd,msg,sizeof(msg),0);
        if(n<=0)//读取来自服务器的数据出错
            break;
        write(STDOUT_FILENO,msg,n);
        printf("输入：");
        //fgets(msg,sizeof(msg),stdin);可代替下面两行
        scanf(" %[^\n]",msg);
        strcat(msg,"\n");//追加换行符
        write(fd,msg,strlen(msg));//发送到服务器
        //send(fd,msg,strlen(msg),0);
        if(msg[0]=='q')
            break;
    }
    close(fd);
    return 0;
}

-------------------------------------------------------------------
/* ip地址格式转换 */int main()
{
    in_addr_t nip;
    char sip[16];
    /* "点分十进制"转换成 "二进制整数",以在 network address结构中使用 */
    inet_pton(AF_INET,"192.168.182.10",&nip);
    unsigned char* p=(unsigned char*)&nip;
    int i;
    for(i=0;i<4;i++)
    {
        printf("%02x",*p++);
    }
    printf("\n");
    inet_ntop(AF_INET,&nip,sip,sizeof(sip));
    puts(sip);
    return 0;
}

-------------------------------------------------------------------
/* 条件变量 */
int flag=0;
pthread_mutex_t m;
pthread_cond_t c=PTHREAD_COND_INITIALIZER;
void* thread1(void* p)
{
    for(;;)
    {
        pthread_mutex_lock(&m);
        if(flag==0)
            pthread_cond_wait(&c,&m);//进入等待，自动解锁互斥量，等到通知后加锁互斥量，结束等待
        pthread_mutex_unlock(&m);
        write(1,p,1);
        sleep(1);
    }
}
int main()
{
    pthread_t id1,id2;
    pthread_mutex_init(&m,NULL);
    pthread_create(&id1,NULL,thread1,".");
    pthread_create(&id2,NULL,thread1,"*");
    for(;;)
    {
        char ch;
        scanf(" %c",&ch);
        pthread_mutex_lock(&m);
        if(ch=='a')
            flag=1,pthread_cond_signal(&c);
        else if(ch=='b')
            flag=1,pthread_cond_broadcast(&c);
        else
            flag=0;
        pthread_mutex_unlock(&m);
    }
    return 0;
}

-------------------------------------------------------------------
/* 互斥量 */
const char* list[10]={"aa","dd","tt","rr","ww","oo","jj","ii","ss","yy"};
int pos=0;//关键数据，用互斥量控制对它的访问
pthread_mutex_t m=PTHREAD_MUTEX_INITIALIZER;
void* func(void* p)
{
    for(;;)
    {
        pthread_mutex_lock(&m);//访问pos前先加锁互斥量
        if(pos>=10)
            break;
        printf("%s号为%s服务\n",(char*)p,list[pos]);
        pos++;
        pthread_mutex_unlock(&m);//访问完毕pos解锁
        sleep(3);//模拟服务时间
    }
    pthread_mutex_unlock(&m);//队列空了互斥量解锁
}
int main()
{
    pthread_t id1,id2,id3;
    pthread_create(&id1,NULL,func,"1");
    pthread_create(&id2,NULL,func,"2");
    pthread_create(&id3,NULL,func,"3");
    pthread_join(id1,NULL);
    pthread_join(id2,NULL);
    pthread_join(id3,NULL);
    return 0;
}

-------------------------------------------------------------------
/* 线程同步 */
sem_t s;
void* func(void* p)
{
    int i;
    int *a=p;
    for(i=0;i<10;i++)
    {
        sem_wait(&s);//等待主线程输入一个数据
        int t=a[i];
        int j;//插入法排序
        for(j=i;j>0&&t<a[j-1];j--)
            a[j]=a[j-1];
        a[j]=t;
        usleep(1);
    }
}
int main()
{
    int a[10];
    sem_init(&s,0,0);
    pthread_t id;
    pthread_create(&id,NULL,func,a);
    int i;
    for(i=0;i<10;i++)
    {
        printf("请输入第%d个数据：",i+1);
        scanf("%d",&a[i]);
        sem_post(&s);//信号量值+1给辅助线程wem_wait放行
    }
    usleep(1);//等待最后一个数据排序完毕
    for(i=0;i<10;i++)
    {
        printf("%d ",a[i]);
    }
    printf("\n");
    sem_destroy(&s);
    return 0;
}

-------------------------------------------------------------------
/* 多线程 */
void* thread(void* p)
{
    for(;;)
    {
        printf("%s",(char*)p);
        fflush(stdout);
        sleep(1);
    }
    return NULL;
}
int main()
{
    pthread_t id;
    pthread_create(&id,NULL,thread,".");
    sleep(5);
    pthread_cancel(id);//请求辅助线程终止
    puts("------------------");
    sleep(3);
    pthread_exit(NULL);//本线程终止
    puts("+++++++++++++++++++");
    return 0;
}

-------------------------------------------------------------------
/* 守护进程 */
int main()
{
    daemon(0,0);//把进程设置为服务进程
    chdir(getpwuid(getuid())->pw_dir);//取得主目录,并设置主目录为当前目录。
    char c='Z';
    for(;;)
    {
        int fd=open("letter",O_RDWR|O_CREAT,0600);
        read(fd,&c,1);
        if(++c>'Z')
            c='A';
        lseek(fd,0,SEEK_SET);
        write(fd,&c,1);
        close(fd);
        sleep(1);
    }
    return 0;
}

-------------------------------------------------------------------
/* 信号量 */
int main()
{
    int id=semget(0x8888,1,IPC_CREAT|0600);
    if(id==-1)
    {
        perror("semget");
        return -1;
    }
    semctl(id,0,SETVAL,5);//信号量的值为5
    int i;
    for(i=0;i<10;i++)
    {
        if(fork()==0)
        {
            struct sembuf sb;
            sb.sem_num=0;
            sb.sem_op=-1;
            sb.sem_flg=SEM_UNDO;
            while(semop(id,&sb,1)==-1)
            {}
            srand(getpid());
            printf("%d进程开始工作\n",getpid());
            sleep(rand()%16+5);//工作5～20s
            printf("%d进程工作完毕\n",getpid());
            sb.sem_op=+1;
            semop(id,&sb,1);//信号量+1
            exit(0);
        }
    }//控制同时只有5个子进程在工作
    while(wait(NULL)!=-1);
    puts("全部子进程结束");
    semctl(id,0,IPC_RMID,NULL);

    return 0;
}

-------------------------------------------------------------------
/* 消息队列收发数据 */
typedef struct{
    long type;
    char name[20];
    int age;
    float score;
}msg;

int main()
{
    int id=msgget(0x9999,0);//纯取得消息队列
    if(id==-1)
    {
        perror("msgget");
        return -1;
    }
    long type;
    msg m;
    printf("请输入想取的消息类型（0表示随意）：\n");
    scanf("%ld",&type);
    if(msgrcv(id,&m,sizeof(m)-sizeof(long),type,IPC_NOWAIT)==-1)
    {
        puts("没有这个类型的消息");
    }
    else
    {
        printf("类型：%ld\n姓名：%s\n年龄：%d\n成绩：%g\n",m.type,m.name,m.age,m.score);
    }
    return 0;
}
int main()
{
    int id=msgget(0x9999,IPC_CREAT|0600);
    printf("id=%d\n",id);
    if(id==-1)
    {
        return -1;
    }
    msg m;
    printf("请输入类型、姓名、年龄和成绩：\n");
    scanf("%ld%s%d%f",&m.type,m.name,&m.age,&m.score);
    msgsnd(id,&m,sizeof(m)-sizeof(long),0);//数据部分的长度不包括类型
    return 0;
}

-------------------------------------------------------------------
/* 共享内存中收放入数据 */
int main()
{
    int id=shmget(0x8888,100,IPC_CREAT|0644);
    printf("id=%d\n",id);
    char* p=shmat(id,NULL,0);
    if(p==(char*)-1)
    {
        return -1;
    }
    strcpy(p,"hello");
    shmdt(p);
    return 0;
}
int main()
{
    int id=shmget(0x8888,0,0);//取得共享内存对象不关心大小和权限
    if(id==-1)
    {
        return -1;
    }
    char* p=shmat(id,NULL,SHM_RDONLY);//只读
    if(p==(char*)-1)
    {
        return -1;
    }
    puts(p);
    shmdt(p);
    shmctl(id,IPC_RMID,0);
    return 0;
}

-------------------------------------------------------------------
/* 匿名本地网络 */
int main()
{
    int s[2];//套接字对，也是文件描述符
    socketpair(AF_LOCAL,SOCK_STREAM,0,s);
    int n;
    char buf[100];
    if(fork()==0)
    {
        while((n=read(s[0],buf,sizeof(buf)))>0)
        {
            int i;
            --n;//保留末尾的换行符
            for(i=0;i<n/2;i++)
            {//把内容颠倒顺序
                char c=buf[i];
                buf[i]=buf[n-1-i];
                buf[n-1-i]=c;
            }
            write(s[0],buf,n+1);
        }
    }
    else
    {
        for(;;)
        {
            n=read(STDIN_FILENO,buf,sizeof(buf));//读取键盘输入
            write(s[1],buf,n);//发送到子进程

            n=read(s[1],buf,sizeof(buf));//读取子进程返回的数据
            write(STDIN_FILENO,buf,n);//显示到屏幕上
        }
        close(s[1]);
    }
    return 0;
}

-------------------------------------------------------------------
/* 命名管道 */
typedef struct {
    char name[20];
    int age;
    double weight;
}Person;

int main()
{
    mkfifo("pipe",0664);
    int fd=open("pipe",O_WRONLY);
    if(fd==-1)
    {
        perror("open");
        return -1;
    }
    puts("打开成功");
    printf("请输入姓名、年龄和体重：\n");
    Person x;
    scanf("%s%d%lf",x.name,&x.age,&x.weight);
    write(fd,&x,sizeof(x));
    close(fd);
    sleep(10);
    unlink("pipe");
    return 0;
}
int main()
{
    int fd=open("pipe",O_RDONLY);
    if(fd==-1)
    {}
    if(read(fd,&x,sizeof(x))!=sizeof(x))
    {
        perror("read");
        return -1;
    }
    printf("姓名：%s\n年龄：%d\n体重：%g\n",
            x.name,x.age,x.weight);
    close(fd);
}

-------------------------------------------------------------------
/* 管道 */
int main()
{
    int fd[2];
    pipe(fd);
    char buf[100];
    if(fork()==0)
    {
        close(fd[1]);//关闭写端保留读端
        int n;
        while((n=read(fd[0],buf,sizeof(buf)))>0)
        {
            int i;
            for(i=0;i<n;i++)
            {
                if(islower(buf[i]))
                    putchar(toupper(buf[i]));
                else if(isupper(buf[i]))
                    putchar(tolower(buf[i]));
                else
                    putchar(buf[i]);
            }
        }
        close(fd[0]);
    }
    else
    {
        int n;
        close(fd[0]);
        for(;;)
        {
            n=read(STDIN_FILENO,buf,sizeof(buf));
            if(buf[0]=='q')
                break;
            write(fd[1],buf,n);
        }
        close(fd[1]);
    }
    return 0;
}

-------------------------------------------------------------------
/* 阻塞信号 */
int main()
{
    sigset_t newset,oldset;
    sigemptyset(&newset);
    sigaddset(&newset,SIGINT);
    sigaddset(&newset,SIGTERM);
    sigprocmask(SIG_BLOCK,&newset,&oldset);//设置屏蔽
    sleep(10);

    sigset_t temp;
    sigpending(&temp);
    puts(sigismember(&temp,SIGINT)?"sigint":"noint");
    puts(sigismember(&temp,SIGTERM)?"sigterm":"noterm");
    sigprocmask(SIG_SETMASK,&oldset,NULL);//恢复信号
    puts("没有ctrl+c信号来过");
    return 0;
}

-------------------------------------------------------------------
/* 带参的信号传递 */

void func(int sig,siginfo_t* info,void* p)
{
    printf("收到信号,来自用户%d的进程%d，附带参数为%d\n",
            info->si_uid,info->si_pid,info->si_value.sival_int);
}
int main()
{
    struct sigaction act,oldact;

    act.sa_sigaction=func;//设置带参信号处理函数
    sigemptyset(&act.sa_mask);//不用屏蔽什么信号
    act.sa_flags=SA_SIGINFO;
    sigaction(SIGUSR2,&act,NULL/*&oldact*/);

    if(fork()==0)//子进程
    {
        printf("uid=%d,pid=%d\n",getuid(),getpid());
        union sigval v;
        v.sival_int=2013;//设置要传递的参数
        sigqueue(getppid(),SIGUSR2,v);//发送信号和参数
        sleep(1);
    }
    else
    {
        pause();
    }
    return 0;
}

-------------------------------------------------------------------
/* 信号集 */
int main()
{
    sigset_t ss;
    sigemptyset(&ss);
    puts(sigismember(&ss,SIGINT)?"sigint":"noint");
    puts(sigismember(&ss,SIGTERM)?"sigterm":"noterm");
    sleep(3);

    sigaddset(&ss,SIGINT);
    sigaddset(&ss,SIGTERM);
    puts(sigismember(&ss,SIGINT)?"sigint":"noint");
    puts(sigismember(&ss,SIGTERM)?"sigterm":"noterm");
    return 0;
}

-------------------------------------------------------------------
/* 重入问题 */

void func(int sig)
{
    getpwnam("root");
    //...
}
int main()
{
    signal(SIGINT,func);
    struct passwd* p=getpwnam("pangchaowei");
    sleep(10);
    printf("uid=%d\n",p->pw_uid);
    return 0;
}

-------------------------------------------------------------------
void child()
{
    printf("pid=%d\n",getpid());
    pause();
}
int main()
{
    int cid=fork();
    if(cid==0)
    {
        child();
    }
    int i;
    for(i=0;i<5;i++)
    {
        if(fork()==0)
        {
            child();
        }
    }
    //下面父进程才会执行
    sleep(5);
    printf("kill第一个子进程\n");
    kill(cid,SIGTERM);
    sleep(3);
    puts("向本组所有进程发信号");
    signal(SIGTERM,SIG_IGN);//父进程忽略SIGTERM信号
    kill(0,SIGTERM);
    sleep(5);
    puts("end");
    return 0;
}

-------------------------------------------------------------------
void timeout(int sig)
{
    puts("时间到");
}
int main()
{
    signal(SIGALRM,timeout);
    struct itimerval iv;
    iv.it_value.tv_sec=5;//第一次定时5s到
    iv.it_value.tv_usec=0;
    iv.it_interval.tv_sec=10;//以后每10s一次
    iv.it_interval.tv_usec=0;
    setitimer(ITIMER_REAL,&iv,NULL);
    for(;;)
    {
        sleep(1);
    }
    return 0;
}

-------------------------------------------------------------------
void func(int sig)
{//一个信号可能有多个子进程结束
    int info;
    pid_t cid;
    while((waitpid(-1,&info,WNOHANG))>0)
    {
        printf("%d结束，返回%d\n",cid,WEXITSTATUS(info));
    }
}
int main()
{
    int i;
    system("clear");
    signal(SIGCHLD,func);
    for(i=0;i<10;i++)
    {//产生10个子进程
        if(fork()==0)
        {
            int j;
            for(j=0;j<20;j++)
            {
                sleep(1);
            }
            exit(c);
        }
    }
    //父进程
    for(;;)
    {
        sleep(100);
    }
    return 0;
}

-------------------------------------------------------------------
/* 信号处理函数 */
void func(int sig)
{
    switch(sig)
    {
        case SIGINT:puts("我不怕ctrl+c");break;
        case SIGTERM:puts("想杀我，没门");break;
        case SIGTSTP:puts("我是不会停滴");break;
    }//kill -9(或信号名字) 进程id 可杀
}
int main()
{
    signal(SIGINT,func);//登记
    signal(SIGTERM,func);
    signal(SIGTSTP,func);
    printf("pid=%d\n",getpid());
    while(1)
    {
        sleep(5);
    }
    return 0;
}

/* ALARM信号 */int cnt=0;
void func(int sig)
{
    printf("输入速度是每小时%d字\n",36*cnt);
    exit(0);
}
int main()
{
    signal(SIGALRM,func);
    printf("请输入每个字一行：\n");
    alarm(100);//定时100秒，到时会收到SIGNALRM信号
    for(;;)
    {
        char buf[100];
        scanf("%s",buf);
        ++cnt;
    }
    return 0;
}

-------------------------------------------------------------------
int main(int argc,char* argv[])
{//vfork创建子进程不克隆，需要紧接着执行exec函数
    if(vfork()==0)
    {//子进程加载child
        execl("./child","./child","fei",NULL);
        puts("加载child失败");
        exit(-1);
    }
    else
    {//父进程
    }
    return 0;
}

-------------------------------------------------------------------
/* 执行命令 */
int main()
{
    char* argv[]={
        "/bin/ls",
        "-l",
        "-d",
        "/bin",
        NULL//必须用一个NULL作为结束元素
    };
    //execv("/bin/ls",argv);
    execvp("ls",argv);//通过环境变量找可执行文件
    execl("/bin/ls","/bin/ls","-l","-d","/bin",NULL);//execl把execv中的argv所有元素依次摆出来作为参数，包括最后的NUL
    return 0;
}

-------------------------------------------------------------------
/* 多进程 */
int main()
{
    int i;
    char* s="a ";
    for(i=0;i<3;i++)
    {//子进程进入大括号执行，父进程直接进入下一轮循环
        if(fork()==0)
        {
            //....
            exit(i);//子进程到此结束
        }
    }
    //父进程会继续执行到这里
    int info;
    while(1)
    {
        //pid_t child=wait(&info);//等待子进程结束
        pid_t child=waitpid(-1,&info,WNOHANG);
        if(child==-1)
            break;
        if(child!=0)
        {
            printf("%d结束\n",child);
        }
        if(WIFEXITED(info))//用宏判断结束方式
        {
            printf("正常结束，返回值%d\n",WEXITSTATUS(info));
        }
        else
        {
            printf("被信号终止\n");
        }
        write(STDERR_FILENO,".",1);
        sleep(1);
    }
    puts("全部子进程结束");
    pause();//暂停以便查看子进程状态。
    return 0;
}

-------------------------------------------------------------------
/* 多进程 */
int main()
{
    int i;
    char* s="a ";
    for(i=0;i<3;i++)
    {//子进程进入大括号执行，父进程直接进入下一轮循环
        if(fork()==0)
        {
            //....
            exit(i);//子进程到此结束
        }
    }
    //父进程会继续执行到这里
    int info;
    while(1)
    {
        //pid_t child=wait(&info);//等待子进程结束
        pid_t child=waitpid(-1,&info,WNOHANG);
        if(child==-1)
            break;
        if(child!=0)
        {
            printf("%d结束\n",child);
        }
        write(STDERR_FILENO,".",1);
        sleep(1);
    }
    puts("全部子进程结束");
    pause();//暂停以便查看子进程状态。
    return 0;
}

-------------------------------------------------------------------

/* 多进程 */
int main()
{
    int id=getpid();
    fork();
    int newid=getpid();
    if(newid==id)
    {
        printf("是父进程%d\n",newid);
    }
    else
    {
        printf("是子进程%d,父进程%d\n",newid,getppid());
    }
    return 0;
    //或
    if(fork()==0)
    {//子进程
        printf("子进程%d，它的父进程%d\n",getpid(),getppid());
    }
    else：
    {//父进程
        printf("父进程%d，它的父进程%d\n",getpid(),getppid());
    }
    puts("hello");//父子进程都会执行到这里
    return 0
}

-------------------------------------------------------------------
int onefunc()
{
    exit(0);//相当于在main中return 0
    //_exit(0);//立即结束进程，清理工作不会执行
}
int main()
{
    atexit(f1);
    atexit(f2);
    void* q=malloc(10);
    on_exit(f3,q);
    //以上只是登记了f1/f2/f3函数但并没有调用他们
    printf("groupid=%d\n",getpgid(getpid()));
    //程序结束，系统会自动调用f1/f2/f3
    return 0;
}

-------------------------------------------------------------------
int main()
{
    uid_t uid=getuid();
    gid_t gid=getgid();
    pid_t pid=getpid();
    pid_t pp=getppid();
    char name[200];
    gethostname(name,200);
    printf("用户id：%d，组id：%d，进程id：%d，父进程：%d，主机名：%s\n",uid,gid,pid,pp,name);
    pause();//等待遇到某个位置开始，比如ctrl+c
    return 0;
}

-------------------------------------------------------------------
/* 映射文件mmap */
int main()
{
    umask(0);
    int fd=open("mmap",O_RDWR|O_CREAT,0644);
    if(fd<0)
    {
        return -1;
    }
    ftruncate(fd,1024);//把文件截成1k长
    char* p=mmap(0,1024,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);//建立文件和内存的 映射
    if(p==MAP_FAILED)
    {
        return -1;
    }
    for(;;)
    {
        int n=read(STDIN_FILENO,p,1024);//键盘输入
        if(n<=0)
            break;
    }
    munmap(p,1024);//解除映射
    close(fd);
    return 0;
}

-------------------------------------------------------------------
/* 文件内容加锁 */
int main()
{
    int fd=open("day24g.c",O_RDONLY);
    if(fd==-1)
    {
        perror("open");
        return -1;
    }
    struct flock pos;
    pos.l_type=F_RDLCK;//读锁
    pos.l_whence=SEEK_SET;
    pos.start=19;//从离文件头19的地方开始
    pos.l_en=17;//加锁长度27字节
    //pos.l_pid=-1;
    if(fcntl(fd,F_SETLK,&pos)==-1)
    {
        perror("read lock failed");
        return -1;
    }
    puts("lock success");
    //访问文件中加锁区域的数据
    sleep(10);

    if(pos.l_type==F_UNLCK)
        puts("未被加锁");
    else
    {
        puts("已经被加锁");
        printf("进程id:%d\n",pos.l_pid);
        printf("锁的类型:%s\n",pos.l_type==F_RDLCK?"读锁"
                :pos.l_type==F_WRLCK?"写锁":"未加锁");
    }
    return 0;
}

-------------------------------------------------------------------
/*  控制台 */
#include<sys/ioctl.h>#include<fcntl.h>#include<unistd.h>#include<termios.h>

int main()
{
    struct winsize w;
    ioctl(STDIN_FILENO,TIOCGWINSZ,&w);//获取控制台的长宽像素
    printf("row=%d,col=%d\n",w.ws_row,w.ws_col);
    return 0;
}

-------------------------------------------------------------------
/* 文件操作 */
int main()
{
    unsigned int id=0;

    umask(0);//不屏蔽权限
    int fd=open("file",O_RDWR|O_CREAT,0777);
    //if(fd<0){}
    read(fd,&id,sizeof(id));
    ++id;
    lseek(fd,0,SEEK_SET);
    write(fd,&id,sizeof(id));
    close(fd);
    printf("id=%u\n",id);
    return 0;
    /* fd = open()...lseek */
    /* fd = fopen()... fseek */
}

-------------------------------------------------------------------
/*低级文件操作 */
int main(int argc,char* argv[])
{
    int n;
    char buf[1024];

    int fd1=open(argv[1],O_RDONLY);
    int fd2=open(argv[2],O_WRONLY|O_CREAT|O_TRUNC,0664);
    if(fd1<0||fd2<0)
    {
        return -1;
    }
    while( (n=read(fd1,buf,sizeof(buf)))>0 )
    {
        int i;
        for(i=0;i<n;i++)
            buf[i]=~buf[i];//加密
        write(fd2,buf,n);
    }
    close(fd1);
    close(fd2);
    return 0;
}

-------------------------------------------------------------------
/* 符号链接 */
int main()
{
    /*linux -> /usr/src/linux-source-2.6.32 */
    char buf[100];
    int n;
    if((n=readlink("linux",buf,sizeof(buf))) == -1)
    {
        return -1;
    }
    buf[n]=0;//'\0'
    puts(buf); /* /usr/src/linux-source-2.6.32 */
    unlink("linux"); /* 相当于删除linux */
    return 0;
}

-------------------------------------------------------------------
/* 目录操作 */
int main()
{
    char buf[100];

    mkdir("mydir",0755);
    chdir("mydir");
    getcwd(buf,sizeof(buf));//取得绝对路径
    puts(buf);
    chdir("..");
    sleep(10);
    rmdir("mydir");
    return 0;
}

-------------------------------------------------------------------
/* 目录操作 */
#include<dirent.h>
int main()
{
    mkdir("dirTest", 0755);
    DIR* p=opendir(".");//打开目录
    //if(p==NULL){...}
    struct dirent* q;
    while((q=readdir(p))!=NULL)//逐项读取
    {
        if(q->d_name[0]=='.')
            continue;//跳过隐藏文件
        printf("%s\t",q->d_name);
    }
    printf("\n");
    closedir(p);
    return 0;
}

-------------------------------------------------------------------
/* 时间 */
int main()
{
    char buf[100];
    time_t now=time(NULL);
    struct tm* p=localtime(&now);
    strftime(buf,sizeof(buf),"%F %w %T",p); /* 把p中的时间按指定格式存入buf中 */
    puts(buf);
}

-------------------------------------------------------------------
/* rename,symlink,chmod,access,remove 文件操作 */
int main(int argc,char* argv[])
{
    rename(argv[0],"program");//把a.out改名program
    symlink("program","lfr");//给program建符号链接lfr
    chmod("program",0555);//修改权限
    if(access("program",F_OK)==0)puts("program存在");
    if(access("program",R_OK)==0)puts("可读");
    if(access("program",W_OK)==0)puts("可写");
    if(access("program",X_OK)==0)puts("可执行");
}

-------------------------------------------------------------------
/* 获得文件详细信息 */

#include<sys/stat.h>
#include<unistd.h>

int main(int argc,char* argv[])
{
    struct stat s;
    if(lstat(argv[1],&s)!=0)
    {
        return -1;
    }
    if(S_ISREG(s.st_mode)) puts("normal file");
    else if(S_ISDIR(s.st_mode)) puts("directory");
    else if(S_ISLNK(s.st_mode)) puts("link");
    else puts("others");

    printf("权限：%o\n",s.st_mode&0777);


}

printf("硬链接%d,用户名%s,字节数%lu\n",s.st_nlink,getpwuid(s.st_uid)->pw_name,s.st_size);

-------------------------------------------------------------------
/* 低级内存分配 */
#include<sys/mman.h>int main()
{
    char* p=mmap(NULL,200,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0);
    if(p!=MAP_FAILED)
    {
        scanf("%[^\n]",p); /* 通配符 回车之前的字符全部存入 */
        printf("your input is %s\n",p);
        munmap(p,200);
    }
    return 0;
}

-------------------------------------------------------------------
/* 低级内存操作 */
int main()
{
    printf("pagesize=%d\n",getpagesize());
    int* p=sbrk(0);//返回当前终点，有效内存地址不包含终点
    printf("end=%p\n",p);
    //int n=*p;//段错误
    brk(p+8);
    printf("end=%p\n",p);//终点后移8*4字节，操作系统包扩展的这段虚拟内存映射到物理内存，但映射以页为基本单位，实际映射的内存会是一页。
    int i;
    for(i=0;i<12;i++)//越界但不会段错误
        p[i]=10+i;
    for(i=0;i<12;i++)
        printf("%d ",p[i]);
    printf("\n");
    //p[1024]=111;//超越内存页了，段错误
    p[1023]=111;//没有段错误

    printf("p+8=%p\n",p+8);
    printf("+4:%p\n",sbrk(4070));//32+4070超过了一页会映射下一页虚拟内存地址到物理内存。
    p[1024]=111;//正常了
    sbrk(-6);//回退6字节，最后一页的映射就不需要了，操作系统会解除这一页。
    //p[1024]=111;//又段错误
    return 0;
}

-------------------------------------------------------------------
/* 环境变量操作函数 */
int main()
{
    putenv("CLASS=121314");
    char* p=getenv("CLASS");
    if(p)
        puts(p);
    setenv("NAME","heha",1);
    p=getenv("NAME");
    if(p)
        puts(p);
    return 0;
}

-------------------------------------------------------------------
/* main 函数另一个形式*/
int main(int argc,char* argv[],char* env[])

{//env是环境变量字符串数组，以NULL为结束元素
    int i;
    char* p=NULL;
    for(i=0;env[i]!=NULL;i++)
    {
        puts(env[i]);//显示环境变量字符串
        if(strncmp(env[i],"LANG=",5)==0)
            p=env[i]+5;
    }
    if(p!=NULL)
        printf("LANG=%s\n",p);
    return 0;
}


/* 访问环境变量另一种形式 */
extern char** environ;
int main()
{
    int i=0;
    for(i=0;environ[i]!=NULL;i++)
    {
        puts(environ[i]);
    }
    return 0;
}

-------------------------------------------------------------------
/* 动态链接库操作*/
#include<stdio.h>
#include<dlfcn.h>int main()
{
    void* handle;
    void (*fp)(void);

    if(sel==1)
        handle=dlopen("./libone.so",RTLD_NOW);/*打开一个动态链接库*/
    else
        handle=dlopen("./libtwo.so",RTLD_NOW);
    if(handle==NULL)
    {
        puts(dlerror());
        return -1;
    }
    fp=dlsym(handle,"funcName");/*在库中找函数名*/
    if(fp==NULL)
    {
        puts(dlerror());
        return -1;
    }
    fp();
    dlclose(handle);
    return 0;
}

-------------------------------------------------------------------
/* 文件操作位置指针 */

int main()
{
    FILE* pFile=NULL;
    char ch=0;
    pFile=fopen("a.txt","r");
    if(pFile)
    {
        ch=fgetc(pFile);
        printf("%c ",ch);

        rewind(pFile);//位置指针移动到开头

        fseek(pFile,6,SEEK_SET);
        ch=fgetc(pFile);
        printf("%c ",ch);

        fseek(pFile,-4,SEEK_END);//-3代表向前3字节的位置

        printf("%c ",ch);
        printf("位置指针的位置是%ld\n",ftell(pFile));//ftell可获得当前位置指针的位置。
        fclose(pFile);
        pFile=NULL;
    }
    return 0;
}

-------------------------------------------------------------------
/* 文件批量字符处理 fwrite fread 函数 */
int main()
{
    FILE* pFile=NULL;
    int values[3]={1,2,3},num=0;
    pFile=fopen("a.bin","w+b");
    if(pFile)
    {
        num=fwrite(values,sizeof(int),3,pFile);
        fclose(pFile);
        pFile=NULL;
    }

    int res[3]={0},num2=0;
    FILE* pFile2=NULL;
    pFile2=fopen("a.bin","rb");
    if(pFile2)
    {
        num2=fread(res,sizeof(int),3,pFile2);
        printf("%d %d %d\n",res[0],res[1],res[2]);
        fclose(pFile2);
        pFile2=NULL;
    }
    return 0;
}

-------------------------------------------------------------------
/* 文件操作(复制) */
int main()
{
    FILE* pSrc=NULL,*pDest=NULL;
    char ch=0;
    pSrc=fopen("a.txt","r");
    if(pSrc)
    {
        pDest=fopen("b.txt","w");
        if(pDest)
        {
            while(ch!=EOF)
            {
                ch=fgetc(pSrc);
                if(ch!=EOF)
                {
                    fputc(ch,pDest);
                }
            }
            fclose(pDest);
            pDest=NULL;
        }
        fclose(pSrc);
        pSrc=NULL;
    }
    return 0;
}

-------------------------------------------------------------------
/* 指针总结 */
int main()
{
    int num;

    int* pNum;
    int arr[3];

    int (*pArr)[3];//数组指针
    int arr2[2][3];

    int* pArray[3];//指针数组
    int** ppNum;//二级指针，记录一级指针变量的地址

    int f();//函数名称本身代表了函数的开始地址
    int (*p)();//函数指针变量

    int* p();//返回int指针的函数

    NULL; //空地址

    //野指针

    void*; //可以转换成任何类型的地址
}


-------------------------------------------------------------------
/* 内存函数 */
int main()
{
    int* pNum=NULL,n=0,i=0;
    //pNum=(int*)malloc(3*sizeof(int));//不保证内存中都被清零
    pNum=(int*)calloc(3,sizeof(int));//与上句有同样效果。保证所有变量都被清零
    if(pNum)
    {
        for(i=0;i<=2;i++)
        {
            *(pNum+i)=i;
            printf("*(pNum+%d)=%d\n",i,*(pNum+i));
        }

        int* pNum1=realloc(pNum,6*sizeof(int));
        //调整原来分配的空间，到指定的大小。原来的数值不变。pNum地址可能变，也可能不变，也可能失败（返回NULL）原来分配的还在。
        if(pNum1)
        {
            pNum=pNum1;
        }
        else
        { }
        for(i=0;i<=5;i++)
        {
            printf("*(pNum+%d)=%d\n",i,*(pNum+i));
        }
        free(pNum);
        pNum=NULL;
    }
    return 0;
}

-------------------------------------------------------------------
/* 枚举 */
int main()
{
    enum _season{SPR,SUM,AUT=6,WIN};

    enum _season season;
    season=SUM;//枚举变量season可以有4个不同的值
    printf("season=%d\n",season);
}

-------------------------------------------------------------------
#define STR(n) #n   //宏运算符#，在n的前、后加上",这个运算符放在一个参数前面表示，把这个参数转换成字符串字面值。
#define GLOBAL(n) g_##n // ##把g_和参数n连接起来，为全局变量加上一个"头"

int main()
{
    printf("%p\n","xyz");//字符串其实是用首字符的地址表示的
    printf("%p\n","xyz");//两次输出相同，因为字面值的字符串不能修改，运行时会被合并成同一个
    printf("%p\n","xyza");//稍有不同就不会合并

    char str[]="abc";//会把字符串首地址后面的字符复制到字符数组
    printf("sizeof(str)=%d\n",sizeof(str));//输出4,有\0结束符
    //char str[]={'a','b','c','\0'};//等价

    //char str[10];
    fgets(str,10,stdin);//安全从键盘读取字符串的方法

    printf("%s\n",STR(5-3));//输出5-3
}

-------------------------------------------------------------------
/* 数字时钟练习 */

int main()
{
    int h=0,m=0,s=0;
    int t=0;
    while(1)
    {
        t=time(0);//time(获得的是0时区的时间)
        s=t%60;
        m=t%3600/60;
        h=t%(24*3600)/3600;
        h=(h+8)%24;//东8区时间
        printf("%02d:%02d:%02d\r",h,m,s);//'\r'覆盖上一次输出
        fflush(stdout);//强制输出

        sleep(1);//unistd.h
    }
    return 0;
}
-------------------------------------------------------------------------------------------------
/*递归*/

int factorial(int n)
{
    if(1==n) {
        return 1;
    } else {
        return n*factorial(n-1);
    }
}

int common_divisor(int m,int n)
{
    if(m<n) {
        int temp=m;m=n;n=temp;
    }
    if(!(m%n)) {
        return n;
    } else {
        common_divisor(n,m%n);
    }

}
----------------------------------------------------------------------
/*  结构体对齐和补齐    内存分配对齐，地址是变量大小的整数倍。
*   int类型变量放在地址能被4整除的地方。
*/
#include<stdio.h>

typedef struct
{
    char a1;
    char a2;
    int num1;
}JieGou;

typedef struct
{
    int num1;
    char a1;
    char a2;
}JieGou1;

typedef struct
{
    char a1;
    int num1;
    char a2;
}JieGou2;

int main()
{
    printf("sizeof(JieGou)=%d\n",sizeof(JieGou));//输出8
    printf("sizeof(JieGou1)=%d\n",sizeof(JieGou1));//也输出8，由补齐造成的。
    printf("sizeof(JieGou2)=%d\n",sizeof(JieGou2));//也输出12,因此声明时最好同类型的放在一起
    return 0;
}
----------------------------------------------------------------------------
/*    模拟登录练习     */

#include<stdio.h>
#include<string.h>
int main()
{
    char str1[]="admin\n";
    char str2[]="123456\n";
    char name[10],passwd[10];
    int i=0;
    for(i=0;i<3;i++)
    {
        printf("please input your name:");
        fgets(name,10,stdin);
        printf("please input your password:");
        fgets(passwd,10,stdin);

        if(strcmp(name,str1)||strcmp(passwd,str2))
        {
            printf("your name or password was wrong.\n");
            continue;
        }
        break;
    }
    if(i<3)
        printf("Login in sucessfully.\n");
    else
        printf("Login in failed!\n");

    return 0;


-----------------------------------------------------------------------------
二维数组当参数
int main()
{
    int bb[2][3]={1,2,3,4,5,6};
    display(bb,2,3);//二维数组做参数只能当成一维数组使用

    return 0;
}

void display(int bb[],int row,int col)
{
    for(int i=0;i<row;i++)
    {
        for(int j=0;j<col;j++)
        {
            printf("%d ",bb[i*col+j]);
        }
    }
    printf("\n");
}
-------------------------------------------------------------------------------------------------
exit函数
 exit(0);//调用exit函数,结束程序,exit()中的0作为main函数的返回值
数组初始化
int array[3][2]={{1,2},{3,4},{5,6}};

随机数生成
srand(time(0));
printf("%d\n",rand());
-------------------------------------------------------------------------
/* scanf  */
#include<stdio.h>

int main()
{
    //输出
    printf("hello word!");
    fflush(stdout);//刷新显示
    //输入
    int i=0,j=0;
    printf("please input the first number:");
    while(!scanf("%d",&i))//当scanf读取失败时返回0
    {
        scanf("%*[^\n]");//清除本次输入的数据
        scanf("%*c");
        printf("please input a number again!");
    }
    scanf("%*[^\n]");//消除本次输入对下次的影响
    scanf("%*c");

    printf("please input the second number:");
    scanf("%d",&j);
    printf("i=%d,j=%d\n",i,j);

    return 0;
}

----------------------------------------------------------------------------
/* * realize 'ls -l' command */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>

void list_detail(void);
void show_detail(const char *name);
void print_type(int mode);
void print_access(int mode);

int main(int argc, char *argv[])
{
    if (argc > 2)
    {
        printf("Usage: %s [path]\n", argv[0]);
        return 0;
    }
    else if (argc == 2)
    {
        if (chdir(argv[1]) < 0)
        {
            perror("chdir");
            return -1;
        }
    }
     list_detail();
}

void show_detail(const char *name)
{
    struct stat s;
    char buf[20] = {0};

    lstat(name, &s);
    print_type(s.st_mode);
    print_access(s.st_mode);

    printf("%2d ", s.st_nlink);
    printf("%7s ", getpwuid(s.st_uid)->pw_name);
    printf("%7s ", getgrgid(s.st_gid)->gr_name);
    printf("%10lu ", s.st_size);
    strftime(buf, sizeof(buf), "%F %T", localtime(&s.st_mtime));
    printf("%20s %s\n", buf, name);
}

void print_access(int mode)
{
    const char *acc = "rwx";
    int i = 0;

    for(i = 0; i < 9; i++)
    {
        putchar(mode & 0400 ? acc[i%3] : '-');
        mode <<= 1;
    }
}

void print_type(int mode)
{
    if (S_ISREG(mode))  putchar('-');
    else if (S_ISDIR(mode)) putchar('d');
    else if (S_ISLNK(mode)) putchar('l');
    else if (S_ISFIFO(mode)) putchar('p');
    else if (S_ISSOCK(mode)) putchar('s');
    else if (S_ISCHR(mode)) putchar('c');
    else if (S_ISBLK(mode)) putchar('b');
    else putchar('*');
}

void list_detail(void)
{
    struct dirent *pr = NULL;
    DIR *pd = NULL;
    pd = opendir(".");
    if (pd == NULL)
    {
        perror("opendir");
        return;
    }
    while ((pr = readdir(pd)) != NULL)
    {
        if (pr->d_name[0] == '.')
            continue;
         show_detail(pr->d_name);
    }
}   
 

